package com.bizmda.bizsip.app.checkrule;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.json.JSONObject;
import com.bizmda.bizsip.common.BizException;
import com.bizmda.bizsip.common.BizResultEnum;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author shizhengye
 */
@Slf4j
public class FieldCheckRuleHelper {
    private FieldCheckRuleHelper() {

    }

    private static final ExecutorService fieldAssertExecutorService = ThreadUtil.newExecutor(Runtime.getRuntime().availableProcessors());

    public static List<FieldChcekRuleResult> checkFieldRule(JSONObject jsonObject, List<FieldCheckRule> fieldCheckRuleList, CheckMode checkMode) throws BizException {
        CompletionService<FieldChcekRuleResult> service = new ExecutorCompletionService<>(fieldAssertExecutorService);
        List<Future<FieldChcekRuleResult>> futureList = new ArrayList<>();
        for (FieldCheckRule fieldCheckRule : fieldCheckRuleList) {
            Future<FieldChcekRuleResult> future = service.submit(new FieldCheckRuleThread(jsonObject, fieldCheckRule));
            futureList.add(future);
        }
        List<FieldChcekRuleResult> fieldChcekRuleResultList = new ArrayList<>();
        for (int i = 0; i < fieldCheckRuleList.size(); i++) {
            if (takeFieldCheckRuleResult(checkMode, service, futureList, fieldChcekRuleResultList)) {
                return fieldChcekRuleResultList;
            }
        }
        return fieldChcekRuleResultList;
    }

    private static boolean takeFieldCheckRuleResult(CheckMode checkMode, CompletionService<FieldChcekRuleResult> service, List<Future<FieldChcekRuleResult>> futureList, List<FieldChcekRuleResult> fieldChcekRuleResultList) throws BizException {
        Future<FieldChcekRuleResult> take;
        try {
            take = service.take();
        } catch (InterruptedException e) {
            log.error("域校验计算被中断",e);
            Thread.currentThread().interrupt();
            throw new BizException(BizResultEnum.CHECKRULE_FIELD_CHECK_THREAD_ERROR, e);
        }
        FieldChcekRuleResult fieldChcekRuleResult;
        try {
            fieldChcekRuleResult = take.get();
        }
        catch (InterruptedException e) {
            log.error("域校验计算被中断",e);
            Thread.currentThread().interrupt();
            throw new BizException(BizResultEnum.CHECKRULE_FIELD_CHECK_THREAD_ERROR, e);
        }
        catch (ExecutionException e) {
            Throwable throwable = e.getCause();
            if (throwable instanceof BizException) {
                throw (BizException) throwable;
            }
            throw new BizException(BizResultEnum.CHECKRULE_FIELD_CHECK_THREAD_ERROR, e);
        }
        if (fieldChcekRuleResult != null) {
            if (checkMode == CheckMode.ONE) {
                for (Future<FieldChcekRuleResult> future : futureList) {
                    future.cancel(true);
                }
                fieldChcekRuleResultList.add(fieldChcekRuleResult);
                return true;
            }
            else {
                fieldChcekRuleResultList.add(fieldChcekRuleResult);
            }
        }
        return false;
    }
}
